package com.apes.scm.pur.redemption.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.outbox.OutboxPayloadWrapper;
import com.apes.framework.plugin.outbox.OutboxSubscriberService;
import com.apes.framework.plugin.outbox.annotation.OutboxSubscriber;
import com.apes.framework.util.Arith;
import com.apes.framework.util.MapUtil;
import com.apes.pi.service.PiManager;
import com.apes.scm.account.account.model.InventoryBatch;
import com.apes.scm.account.account.repository.InventoryBatchRepository;
import com.apes.scm.account.account.service.InventoryService;
import com.apes.scm.account.account.service.ProductAccountService;
import com.apes.scm.account.tax.service.TaxService;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.pur.purchaseOrder.model.PurchaseOrder;
import com.apes.scm.pur.purchaseOrder.model.PurchaseOrderItem;
import com.apes.scm.pur.purchaseOrder.repository.PurchaseOrderRepository;
import com.apes.scm.pur.redemption.model.Redemption;
import com.apes.scm.pur.redemption.repository.RedemptionRepository;
import com.apes.scm.stock.transfer.model.Pick;
import com.apes.scm.stock.transfer.repository.PickRepository;
import com.apes.scm.voucher.model.Voucher;
import com.apes.scm.yy.QueryCommonService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import java.util.*;

@Service("redemptionService")
public class RedemptionService extends DomainService {

    @Autowired
    private PickRepository pickRepository;
    @Autowired
    private RedemptionRepository redemptionRepository;
    @Autowired
    private PurchaseOrderRepository purchaseOrderRepository;
    @Autowired
    private TaxService taxService;
    @Autowired
    private ProductAccountService productAccountService;
    @Autowired
    private OutboxSubscriberService outboxSubscriberService;
    @Autowired
    private PiManager piManager;
    @Autowired
    private InventoryService inventoryService;
    @Autowired
    private InventoryBatchRepository inventoryBatchRepository;
    @Autowired
    private PartyRoleRepository partyRoleRepository;
    @Autowired
    private QueryCommonService queryCommonService;

    /**
     * 新增
     * @param simpleRequest
     * @return
     */
    public Redemption create(SimpleRequest simpleRequest) {
        Redemption redemption = simpleRequest.getO(Redemption.class);
        redemption.setState("sent");
        redemption.setCreateDate(new Date());
        redemption.setCreateUid(simpleRequest.getPerson());
        Redemption redemption1 = redemptionRepository.saveAndFlush(redemption);
        this.updateInventory(redemption1, "入库冲红新增", "insert");
        return redemption1;
    }

    /**
     * 修改
     * @param simpleRequest
     * @return
     */
    public Redemption update(SimpleRequest simpleRequest) {
        Redemption redemption = simpleRequest.getO(Redemption.class);

        Redemption oldRedemption = redemptionRepository.findOne(redemption.getId());
        this.updateInventory(oldRedemption, "入库冲红修改", "update1");

        Redemption redemption1 = redemptionRepository.saveAndFlush(redemption);
        this.updateInventory(redemption1, "入库冲红修改", "update2");
        return redemption1;
    }

    /**
     * 删除
     * @param simpleRequest
     */
    public String delete(SimpleRequest simpleRequest) {
        Redemption redemption = simpleRequest.getO(Redemption.class);
        this.updateInventory(redemption, "入库冲红删除", "delete");
        redemption.setState("delete");
        redemption.setDeleteDate(new Date());
        redemption.setDeleteUid(simpleRequest.getPerson());
        redemptionRepository.saveAndFlush(redemption);
        return "删除成功！";
    }


    /**
     * 审核
     * @param simpleRequest
     * @return
     */
    public Redemption approve(SimpleRequest simpleRequest) {
        Redemption redemption = simpleRequest.getO(Redemption.class);
        redemption.setState("approve");
        redemption.setApproveUid(simpleRequest.getPerson());
        redemption.setApproveDate(new Date());
        redemption = redemptionRepository.saveAndFlush(redemption);

        PurchaseOrder purchaseOrder = this.appendPickData(redemption.getOrigin(), redemption); // 修改保管数、拼接采购订单数据
        PurchaseOrder getPurchaseOrder = invoke("purchase.order.create", MapUtil.mapped(purchaseOrder));
        getPurchaseOrder = invoke("purchase.order.approve", MapUtil.mapped(getPurchaseOrder));

        invoke("stock.productRequire.redemptionReductionArriveQty", MapUtil.mapped(getPurchaseOrder)); // 更新要货实际订货数量

        Voucher voucher = invoke("voucher.create", MapUtil.mapped(SpringManager.getBean(RedemptionVoucherService.class).flowRedemptionVoucher(redemption)));
        if ("IM_OWN".equals(voucher.getInventoryMode()) && "done".equals(voucher.getState())) invoke("invoice.create", invoke("voucher.flow.invoice", MapUtil.mapped(voucher)));

        this.updatePurchaseWaitSL(redemption); // 修改老框架采购订单入库数量
        return redemption;
    }

    /**
     * 修改保管数、拼接产生采购订单数据
     * @param purchaseOrderId
     * @return
     */
    private PurchaseOrder appendPickData(String purchaseOrderId, Redemption redemption) {
        PurchaseOrder purchaseOrder = purchaseOrderRepository.findOne(purchaseOrderId);

        PurchaseOrder newPurchaseOrder = new PurchaseOrder();
        List<PurchaseOrderItem> purchaseOrderItemSet = new ArrayList<>();
        redemption.getRedemptionItems().forEach(redemptionItem -> {
            // 保管数: -
            productAccountService.setProductCustody(redemptionItem.getProduct(), redemption.getLocation(), redemptionItem.getUom(), redemptionItem.getQty(), redemption.getInnerBusinessType(),
                    redemption.getId(), String.valueOf(redemptionItem.getId()), "入库冲红单审核", redemption.getCompany());

            // 拼接采购订单, 准备生成交货单
            purchaseOrder.getPurchaseItems().forEach(purchaseOrderItem -> {
                if (redemptionItem.getProduct().getId().equals(purchaseOrderItem.getProduct().getId())) {
                    double redemptionQty = -1 * redemptionItem.getQty();
                    PurchaseOrderItem newPurchaseItem = new PurchaseOrderItem();

                    // 计算税率价格
                    Map taxmap = this.calcTax(purchaseOrder.getCompany().getId(), purchaseOrderItem.getTax().getId(), String.valueOf(purchaseOrderItem.getPriceUnit()), String.valueOf(redemptionQty));
                    this.makeupPurchaseOrderItem(newPurchaseItem, purchaseOrderItem, taxmap, redemptionQty);
                    purchaseOrderItemSet.add(newPurchaseItem);
                }
            });
        });
        this.makeupPurchaseOrder(newPurchaseOrder, purchaseOrder, purchaseOrderItemSet, redemption.getId(), redemption.getInnerBusinessType());
        return newPurchaseOrder;
    }

    /**
     * 拼接采购订单
     * @param newPurchaseOrder
     * @param oldPurchaseOrder
     * @param purchaseOrderItemSet
     */
    private void makeupPurchaseOrder(PurchaseOrder newPurchaseOrder, PurchaseOrder oldPurchaseOrder, List<PurchaseOrderItem> purchaseOrderItemSet, String redemptionId, String redemptionBusinessType) {
        newPurchaseOrder.setCompany(oldPurchaseOrder.getCompany());
        newPurchaseOrder.setDept(oldPurchaseOrder.getDept());
        newPurchaseOrder.setClerk(oldPurchaseOrder.getClerk());
        newPurchaseOrder.setContract(oldPurchaseOrder.getContract());
        newPurchaseOrder.setSupplier(oldPurchaseOrder.getSupplier());
        newPurchaseOrder.setMoveType(oldPurchaseOrder.getMoveType());
        newPurchaseOrder.setCarryType(oldPurchaseOrder.getCarryType());
        newPurchaseOrder.setLocation(oldPurchaseOrder.getLocation());
        newPurchaseOrder.setReceiptLocation(oldPurchaseOrder.getReceiptLocation());
        newPurchaseOrder.setDestAddress(oldPurchaseOrder.getDestAddress());
        newPurchaseOrder.setCooperation(oldPurchaseOrder.getCooperation());
        newPurchaseOrder.setNote(oldPurchaseOrder.getNote());
        newPurchaseOrder.setDateOrder(oldPurchaseOrder.getDateOrder());
        newPurchaseOrder.setInvoiceStatus(oldPurchaseOrder.getInvoiceStatus());
        newPurchaseOrder.setScene(oldPurchaseOrder.getScene());
        newPurchaseOrder.setSource(redemptionId);
        newPurchaseOrder.setSourceType(redemptionBusinessType);
        newPurchaseOrder.setSourceTypeName("入库冲红单");
        newPurchaseOrder.setOrigin(oldPurchaseOrder.getId());
        newPurchaseOrder.setOriginBusinessType(oldPurchaseOrder.getInnerBusinessType());
        newPurchaseOrder.setOriginTypeName("采购订单");
        newPurchaseOrder.setSupplierRef(oldPurchaseOrder.getSource());
        newPurchaseOrder.setSupplierType(oldPurchaseOrder.getSourceType());
        newPurchaseOrder.setPurchaseItems(purchaseOrderItemSet);

        double sumAmtTax = Arith.round(oldPurchaseOrder.getPurchaseItems().stream().mapToDouble(purchaseOrderItem -> purchaseOrderItem.getPriceTax()).sum(), 2);
        double sumAmtUntaxed = Arith.round(oldPurchaseOrder.getPurchaseItems().stream().mapToDouble(purchaseOrderItem -> purchaseOrderItem.getPriceSubtotal()).sum(), 2);
        double sumAmtTotal = Arith.round(oldPurchaseOrder.getPurchaseItems().stream().mapToDouble(purchaseOrderItem -> purchaseOrderItem.getPriceTotal()).sum(), 2);
        newPurchaseOrder.setAmtTax(sumAmtTax);
        newPurchaseOrder.setAmtTotal(sumAmtTotal);
        newPurchaseOrder.setAmtWithoutTax(sumAmtUntaxed);
    }

    /**
     * 拼接采购订单明细
     * @param newPurchaseOrderItem
     * @param oldPurchaseOrderItem
     * @param taxmap
     * @param redemptionQty
     */
    private void makeupPurchaseOrderItem(PurchaseOrderItem newPurchaseOrderItem, PurchaseOrderItem oldPurchaseOrderItem, Map taxmap, double redemptionQty) {
        newPurchaseOrderItem.setEffectiveQty(redemptionQty);
        newPurchaseOrderItem.setProductUomQty(redemptionQty);
        newPurchaseOrderItem.setName(oldPurchaseOrderItem.getName());
        newPurchaseOrderItem.setPriceCeiling(oldPurchaseOrderItem.getPriceCeiling());
        newPurchaseOrderItem.setUom(oldPurchaseOrderItem.getUom());
        newPurchaseOrderItem.setTax(oldPurchaseOrderItem.getTax());
        newPurchaseOrderItem.setProduct(oldPurchaseOrderItem.getProduct());
        newPurchaseOrderItem.setQtyInvoiced(oldPurchaseOrderItem.getQtyInvoiced());
        newPurchaseOrderItem.setPriceUnit(oldPurchaseOrderItem.getPriceUnit());

        // 计算税率价格
        newPurchaseOrderItem.setPriceTax((Double) taxmap.get("taxAmt"));
        newPurchaseOrderItem.setPriceSubtotal((Double) taxmap.get("totalExcluded"));
        newPurchaseOrderItem.setPriceTotal((Double) taxmap.get("totalIncluded"));
    }

    /**
     * 计算税率价格
     * @param companyId
     * @param taxId
     * @param priceUnit
     * @param qty
     * @return
     */
    private Map calcTax(String companyId, Long taxId, String priceUnit, String qty) {
        Map getPriceCondition = new HashMap();
        getPriceCondition.put("companyId", companyId);
        getPriceCondition.put("taxId", taxId);
        getPriceCondition.put("priceUnit", priceUnit);
        getPriceCondition.put("qty", qty);

        SimpleRequest request = new SimpleRequest();
        request.setData(getPriceCondition);
        return taxService.computeTaxAmount(request);
    }


    /**
     * 修改库存数
     * @param redemption1
     */
    private void updateInventory(Redemption redemption1, String remark, String operate) {
        redemption1.getRedemptionItems().forEach(redemptionItem -> {
            double qty = redemptionItem.getQty();
            double inventoryBatchQty = -1 * redemptionItem.getQty();
            if ("delete".equals(operate) || "update1".equals(operate)) {
                qty = -1 * qty;
                inventoryBatchQty = redemptionItem.getQty();
            }
            // 可用数
            productAccountService.setProductAvailable(redemptionItem.getProduct(), redemption1.getLocation(), redemptionItem.getUom(), qty,
                    redemption1.getInnerBusinessType(), redemption1.getId(), String.valueOf(redemptionItem.getId()), remark, redemption1.getCompany());

            // 批次冻结
            inventoryService.changeFrostQty(redemptionItem.getInventoryBatch(), redemptionItem.getUom(), inventoryBatchQty, redemption1.getCompany(), redemption1.getInnerBusinessType(), redemption1.getId(), String.valueOf(redemptionItem.getId()), remark);
        });
    }

    /**
     * 修改采购订单订货在途
     * @param redemption
     */
    private void updatePurchaseWaitSL(Redemption redemption) {
        JSONObject oldPurchase = new JSONObject();
        PurchaseOrder purchaseOrder = purchaseOrderRepository.findOne(redemption.getOrigin());
        if ("CD0".equals(purchaseOrder.getSourceType())) {
            oldPurchase.put("CGDDH", purchaseOrder.getSource());
            oldPurchase.put("CKKQID", redemption.getLocation().getId());
            oldPurchase.put("GYSID", queryCommonService.queryContrastPartyCodeGetGysid(purchaseOrder.getSupplier().getId()));
        }

        JSONArray oldCGDDArray = new JSONArray();
        redemption.getRedemptionItems().forEach(redemptionItem -> {
//            productAccountService.setProductPurchasingWay(redemptionItem.getProduct(), redemption.getLocation(), redemptionItem.getUom(), -1 * redemptionItem.getQty(), redemption.getCompany());
            if ("CD0".equals(purchaseOrder.getSourceType())) {
                JSONObject oldCGDDObj = new JSONObject();
                oldCGDDObj.put("SPID", redemptionItem.getProduct().getId());
                oldCGDDObj.put("CHSL", -1 * redemptionItem.getQty());
                oldCGDDObj.put("JLDW", redemptionItem.getUom().getName());
                oldCGDDArray.add(oldCGDDObj);
            }
        });
        if (oldCGDDArray.size() > 0) {
            oldPurchase.put("PUR_CGDDMX", oldCGDDArray);
            outboxSubscriberService.commonSendRequest("scm.redemptionService.updateCGDD_DHZT", redemption.getId(), oldPurchase);
        }
    }



    /**
     * 查询可冲红交货单
     * @param simpleRequest
     */
    public Page<Pick> queryRedemptionPick(SimpleRequest simpleRequest) {
        JSONObject getJO = simpleRequest.getJO();
        JSONArray condition = getJO.getJSONArray("condition");
        if (condition == null) condition = getJO.getJSONObject("group").getJSONArray("filters");

        String id = getJO.getString("key");
        List<String> companyId = new ArrayList<>();
        for (int i = 0, iLen = condition.size(); i < iLen; i++) {
            JSONObject conditionObj = condition.getJSONObject(i);
            String field = conditionObj.getString("field");
            if ("id".equals(field)) id = conditionObj.getString("value");
            else if ("company.id".equals(field)) conditionObj.getJSONArray("value").forEach(company -> companyId.add((String) company));
        }

        int page = getJO.getInteger("page");
        int size = getJO.getInteger("size");
        if (StringUtils.isEmpty(id)) return pickRepository.queryRedemptionPick(companyId, PageRequest.of(page, size));
        if (companyId.size() == 0) return pickRepository.queryRedemptionPickAppendConditionNotCompany(id, PageRequest.of(page, size));
        return pickRepository.queryRedemptionPickAppendCondition(id, companyId, PageRequest.of(page, size));
    }


    /**
     * 查询采购订单获取 另外一部分数据
     * @param simpleRequest
     * @return
     */
    public JSONObject queryPurchaseOrderCalc(SimpleRequest simpleRequest) {
        JSONObject getJO = simpleRequest.getJO();

        List<InventoryBatch> inventoryBatchList = inventoryBatchRepository.accordPickGetInventoryBatch(getJO.getString("pickId"));

        PurchaseOrder purchaseOrder = purchaseOrderRepository.findOne(getJO.getString("id"));
        JSONArray redemptionItemArray = getJO.getJSONArray("redemptionItems");
        redemptionItemArray.forEach(redemptionItem -> {
            JSONObject redemptionItemObj = (JSONObject)redemptionItem;
            redemptionItemObj.put("qty", -1 * redemptionItemObj.getDoubleValue("qty"));
            String rProductId = redemptionItemObj.getJSONObject("product").getString("id");
            double qty = redemptionItemObj.getDoubleValue("qty");

            purchaseOrder.getPurchaseItems().forEach(purchaseOrderItem -> {
                String pProductId = purchaseOrderItem.getProduct().getId();
                double pPriceUnit = purchaseOrderItem.getPriceUnit();
                if (rProductId.equals(pProductId)) {
                    redemptionItemObj.put("priceUnit", pPriceUnit);
                    redemptionItemObj.put("tax", purchaseOrderItem.getTax());
                    redemptionItemObj.put("originItemId", purchaseOrderItem.getId());

                    // 计算税率价格
                    Map taxmap = this.calcTax(getJO.getString("companyId"), purchaseOrderItem.getTax().getId(), String.valueOf(pPriceUnit), String.valueOf(qty));
                    redemptionItemObj.put("priceTax", taxmap.get("taxAmt"));
                    redemptionItemObj.put("priceTotal", taxmap.get("totalIncluded"));
                    redemptionItemObj.put("priceSubtotal", taxmap.get("totalExcluded"));

                    InventoryBatch singleInventoryBatch = inventoryBatchList.stream().filter(inventoryBatch -> inventoryBatch.getProduct().getId().equals(pProductId)).findFirst().get();
                    redemptionItemObj.put("inventoryBatch", singleInventoryBatch);
                }
            });
        });

        double sumAmtTax = Arith.round(redemptionItemArray.stream().mapToDouble(redemptionItemObj -> ((JSONObject)redemptionItemObj).getDoubleValue("priceTax")).sum(), 2);
        double sumAmtUntaxed = Arith.round(redemptionItemArray.stream().mapToDouble(redemptionItemObj -> ((JSONObject)redemptionItemObj).getDoubleValue("priceSubtotal")).sum(), 2);
        double sumAmtTotal = Arith.round(redemptionItemArray.stream().mapToDouble(redemptionItemObj -> ((JSONObject)redemptionItemObj).getDoubleValue("priceTotal")).sum(), 2);

        JSONObject reutnData = new JSONObject();
        reutnData.put("supplier", purchaseOrder.getSupplier());
        reutnData.put("redemptionItems", redemptionItemArray);
        reutnData.put("amtTax", sumAmtTax);
        reutnData.put("amtUntaxed", sumAmtUntaxed);
        reutnData.put("amtTotal", sumAmtTotal);
        reutnData.put("contract", purchaseOrder.getContract());
        reutnData.put("cooperation", purchaseOrder.getCooperation());
        reutnData.put("origin", "Redemption".equals(purchaseOrder.getSourceType())?purchaseOrder.getOrigin() : purchaseOrder.getId());
        reutnData.put("supplierRef", "Redemption".equals(purchaseOrder.getSourceType())?purchaseOrder.getSupplierRef() : purchaseOrder.getSource());
        return reutnData;
    }


    @OutboxSubscriber(id = "scm.redemptionService.updateCGDD_DHZT", name = "修改订货在途")
    public void updateCGDD_DHZT(OutboxPayloadWrapper outboxPayloadWrapper) {
        piManager.synErp("scmCgddService.updateDHZT", outboxPayloadWrapper.getPayload());
    }
}
